這次小櫻遇到一個非常兇猛的Golang牌,究竟是什麼Golang牌可以把企鵝大王給弄倒呢?
我們先前提到的陣列與切片都是以整數為鍵值,而這次要介紹的複合型態,可以「不以整數為鍵值」,而這麼兇猛的卡牌即為「Map」
這個功能其實是可以用 Array 加一些黑科技實作出來,但因為太麻煩而且太常用,所以Golang直接對Map做原生支援
先不管 Map 後面的原理到底是什麼,我們直接宣告一個來試試
package main
import "fmt"
func main(){
// 建立一個由 string 映射到 int 的 map
tall := make(map[string]int)
tall["小櫻"] = 153
tall["知世"] = 155
tall["小狼"] = 156
fmt.Println(tall["小櫻"])
fmt.Println(tall["知世"])
fmt.Println(tall["小狼"])
}
執行結果:
153
155
156
如此一來變可以很快地建立一個以字串為鍵(key)的陣列(?)
長得很像陣列,用起來也很像陣列,但是在Golang中稱為Map,python中稱為Dictionary(字典)、Javascript中稱為Object(物件)、PHP中稱為Associative array(關聯陣列),總之又是一個各家自己看心情命名的東西。
然而,剛剛所用的方法是否太過麻煩!因此有更簡短的宣告方法
package main
import "fmt"
func main(){
// 更簡短地建立一個由 string 映射到 int 的 map
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
fmt.Println(tall["小櫻"])
}
執行結果:
153
在存取時想確定該鍵是否存在該怎麼做呢?
其實可以利用兩個回傳值去存取,第一個會回傳「對應的值」,第二個會回傳「布林值」用來表示該鍵是否存在
package main
import "fmt"
func main(){
// 更快地建立一個由 string 映射到 int 的 map
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
val, ok := tall["小櫻"]
fmt.Println(val, ok)
val, ok = tall["小可"]
fmt.Println(val, ok)
}
執行結果:
153 true
0 false
如果該鍵並不存在,則在讀取該值時其實並不會出錯,而是會以預設值充當對應值回傳,這與部份魔法語言的特性不太一樣
如果只是想確認該值是否存在而不想知道該值,則可以在回傳對應值的部分設為 _
,以免魔仗因為你沒使用宣告出來的變數而噴錯
package main
import "fmt"
func main(){
// 更快地建立一個由 string 映射到 int 的 map
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
_, ok := tall["小狼"]
fmt.Printf("tall[\"小狼\"] 存在嗎?%t", ok) // 第 11 行
}
執行結果:
tall["小狼"] 存在嗎?true
補充一點:在第 11 行 print 的地方當我們要 print 出雙引號時,為了必免被誤認成字串用的雙引號,我們可以在雙引號前加上反斜線
\
去告訴魔仗這是一般的字不是識別字串起頭結尾的字
如同前兩天所教的課程(array 和 slice),map 也可以透過 for + range
的方式進行走訪
package main
import "fmt"
func main(){
// 更快地建立一個由 string 映射到 int 的 map
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
for k, v := range tall{
fmt.Printf("%s的身高是:%dcm\n", k, v)
}
}
執行結果:
小櫻的身高是:153cm
知世的身高是:155cm
小狼的身高是:156cm
注意:走訪時的順序跟加入的順序無關
順序完全是以魔仗底層的咒語依效能而決定
(9/13補充)
利用 for 迴圈走訪時,通常會用 key, value
去接 range 的回傳值,但是,其實也可以只用一個參數,而這個參數預設是 key
,所以如果只想走訪 key
時就可以不用使用 k, _ := range xxx
這種寫法,可以直接寫成 k := range xxx
package main
import "fmt"
func main(){
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
for k := range tall{
fmt.Println(k)
}
}
執行結果:
小櫻
知世
小狼
除了可以新增和修改 map 外,也可以刪除一對鍵值,做法是使用 delete()
package main
import "fmt"
func main(){
// 更快地建立一個由 string 映射到 int 的 map
tall := map[string]int{
"小櫻" : 153,
"知世" : 155,
"小狼" : 156,
}
delete(tall, "小櫻") // 將小櫻從 map 中刪除
for k, v := range tall{
fmt.Printf("%s的身高是:%dcm\n", k, v)
}
}
執行結果:
知世的身高是:155cm
小狼的身高是:156cm
給大家看一下唬爛王山崎↓
而且整部動漫只有李小狼和小櫻會信,笑死,難道是因為同為魔法使的關係,吔~不對,李小狼是魔法使?
話說怎麼最近這幾天的文都不夠ㄎㄧㄤ?吸太少
邦友的按讚是我發文的動力 ,希望各位邦友動動手按個讚!如果有不懂的地方也可以在本文底下留言互動哦!
想了解Map的運作原理可以參考
如果想稍微了解的可以搜尋 Hash map,hash 中文稱雜湊,可以將不同字串轉成不同數字(理想上),利用這個特性再把字串映射到 Array 上,最後為了避免碰撞,再透過 linked list 或紅黑樹等神祕資料結構去儲存。但是這一部份也許以後也不會提到。如果今天主題是 C 語言,就沒有原生的 Map 可以使用;如果是 java 則是額外包成一個物件來用;rust 也是用額外的插件去支持。
Golang 則是直接做原生支持,簡單方便又好用,雖然我覺得 rust 的 hashmap 真的是快掉炸掉就是了。
接下來的課程會越來越難,請新來的魔法使做好心理準備。這系列文進度會越來越快,呈指數型成長。
為了讓新來的魔法使能跟上進度就來出個題目好了
練習1:
利用迴圈印出九九乘法表
提示:for迴圈內可以再加for迴圈
#5 For 迴圈流程控制 | Golang魔法使
練習2:
不呼叫golang提供的排序函式下,由小到到大排序一個整數陣列
arr := [...]int{10, 4, 5, 3, 7, 1, 9, 8}
練習這兩題後應該就能繼續往後的課程了
本文多數圖片來自:
庫洛魔法使第一季第十三集
很用心的教學文
推一個
付個插入排序
func sortArr() {
arr := []int{10, 4, 5, 3, 7, 1, 9, 8}
for i := 1; i < len(arr); i++ {
k := i
for k > 0 && arr[k-1] > arr[k] {
swap(arr, k, k-1)
k--
}
}
}
func swap(arr []int, a int, b int) {
temp := arr[a]
arr[a] = arr[b]
arr[b] = temp
}